package com.iguo.news.common;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author iguo
 * @date 2025/5/15 13:28
 */
public class NewRecommend {

  public static final String DB_URL = "jdbc:mysql://localhost:3306/tushu";
  public static final String USER = "root";
  public static final String PASS = "20040302gyx";

  // 加载用户评分数据的方法
  public static Map<String, Map<String, Double>> loadRatingsFromDB1(Connection conn) throws SQLException {
    Map<String, Map<String, Double>> userRatings = new HashMap<>();
    try (Statement stmt = conn.createStatement();
         ResultSet rs = stmt.executeQuery("SELECT user_id, new_id, score FROM new_score")) {
      while (rs.next()) {
        String userId = rs.getString("user_id");
        String newsId = rs.getString("new_id");
        double rating = rs.getDouble("score");

        userRatings.computeIfAbsent(userId, k -> new HashMap<>()).put(newsId, rating);
      }
    }
    return userRatings;
  }
  // 计算余弦相似度
  public static double cosineSimilarity(Map<String, Double> ratings1,
                                              Map<String, Double> ratings2) {
    // 获取共同评分项目
    Set<String> commonItems = new HashSet<>(ratings1.keySet());
    commonItems.retainAll(ratings2.keySet());
    int commonCount = commonItems.size();

    // 获取所有评分过的项目
    int totalItems1 = ratings1.size();
    int totalItems2 = ratings2.size();

    // 计算共同评分比例
    double coRatedRatio = (double)commonCount / Math.min(totalItems1, totalItems2);

    // 无共同项目则返回0
    if (commonCount == 0) return 0.0;

    // 计算评分相似度部分
    double dotProduct = 0.0, norm1 = 0.0, norm2 = 0.0;
    for (String item : commonItems) {
      double rating1 = ratings1.get(item);
      double rating2 = ratings2.get(item);
      dotProduct += rating1 * rating2;
      norm1 += Math.pow(rating1, 2);
      norm2 += Math.pow(rating2, 2);
    }

    // 防止除以零
    if (norm1 == 0 || norm2 == 0) return 0.0;

    double ratingSimilarity = dotProduct / (Math.sqrt(norm1) * Math.sqrt(norm2));

    // 计算行为相似度部分(只要有共同评分就加分)
    double behaviorSimilarity = Math.min(1.0, commonCount / 5.0); // 5是调节参数

    // 组合两部分相似度
    double combinedSimilarity = 0.3 * ratingSimilarity + 0.7 * behaviorSimilarity;

    // 应用共同评分比例权重
    return combinedSimilarity * coRatedRatio;
  }

  // 找到与目标用户最相似的三个用户
  public static List<String> findTopThreeSimilarUsers(String targetUserId, Map<String, Map<String, Double>> userRatings) {
    System.err.println("当前用户id： "+targetUserId);
    PriorityQueue<Map.Entry<String, Double>> pq = new PriorityQueue<>(
            Comparator.comparingDouble(Map.Entry::getValue)
    );

    for (Map.Entry<String, Map<String, Double>> entry : userRatings.entrySet()) {
      String userId = entry.getKey();
      // 跳过自己
      if (userId.equals(targetUserId)) continue;

      double similarity = cosineSimilarity(userRatings.get(targetUserId), entry.getValue());
      if (Double.isNaN(similarity)) continue;

      if (pq.size() < 3) {
        // 如果队列未满，直接添加
        pq.offer(new AbstractMap.SimpleEntry<>(userId, similarity));
      } else {
        // 如果队列已满，只有当新相似度大于当前最小值时才替换
        if (similarity > pq.peek().getValue()) {
          pq.poll(); // 移除当前最小的
          pq.offer(new AbstractMap.SimpleEntry<>(userId, similarity));
        }
      }
      System.err.println(pq + "   " + userId + "=" + similarity);
    }

    List<String> topUsers = new ArrayList<>();
    while (!pq.isEmpty()) {
      topUsers.add(pq.poll().getKey());
    }
    Collections.reverse(topUsers);
    return topUsers;
  }

  // 基于相似用户推荐新闻
  public static List<Map.Entry<String, Integer>> recommendNewsBasedOnSimilarUsers(
          Map<String, Map<String, Double>> userRatings,
          List<String> similarUsers, String targetUserId) {
    Map<String, Integer> newsVotes = new HashMap<>();

    for (String userId : similarUsers) {
      Map<String, Double> userNews = userRatings.getOrDefault(userId, Collections.emptyMap());
      for (Map.Entry<String, Double> newsRating : userNews.entrySet()) {
        if (!userRatings.get(targetUserId).containsKey(newsRating.getKey())) {
          newsVotes.merge(newsRating.getKey(), 1, Integer::sum);
        }
      }
    }

    List<Map.Entry<String, Integer>> sortedNews = new ArrayList<>(newsVotes.entrySet());
    sortedNews.sort(Map.Entry.<String, Integer>comparingByValue().reversed());
    List<Map.Entry<String, Integer>> recommendNews = new ArrayList<>();
    System.out.println("为用户 " + targetUserId + " 推荐的新闻：");
    for (int i = 0; i < Math.min(12, sortedNews.size()); i++) {
      recommendNews.add(sortedNews.get(i));
      System.out.println("新闻ID: " + sortedNews.get(i).getKey() + ", 被推荐次数: " + sortedNews.get(i).getValue());
    }

    return recommendNews;
  }
}